home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / Libraries / CW GUSI 1.6.4 / src / GUSIFileDispatch.cp < prev    next >
Text File  |  1995-11-05  |  9KB  |  415 lines

  1. /*********************************************************************
  2. Project    :    GUSI                        -    Grand Unified Socket Interface
  3. File        :    GUSIFileDispatch.cp    -    Dispatch calls to their correct recipient
  4. Author    :    Matthias Neeracher
  5. Language    :    MPW C/C++
  6.  
  7. $Log: GUSIFileDispatch.cp,v $
  8. Revision 1.1  1994/12/30  19:59:55  neeri
  9. Initial revision
  10.  
  11. *********************************************************************/
  12.  
  13. #include "GUSIFile_P.h"
  14. #include "GUSIMPW_P.h"
  15. #include <Errors.h>
  16. #include <utime.h>
  17.  
  18. #if GENERATINGCFM
  19. #include <FragLoad.h>
  20. #endif
  21.  
  22. #pragma segment GUSI
  23.  
  24. /************************ External routines *************************/
  25.  
  26. int open(const char * filename, int oflag)
  27. {
  28.     Sockets.InitConsole();
  29.  
  30.     Socket *     sock;
  31.     int            fd;
  32.     GUSIFileRef    ref(filename, FileSocketDomain::willOpen);
  33.  
  34.     if (ref.Domain()) {
  35.         errno = 0;
  36.         
  37.         if (sock = ref.Domain()->open(ref, oflag))
  38.             if ((fd = Sockets.Install(sock)) != -1)
  39.                 return fd;
  40.             else
  41.                 delete sock;
  42.     
  43.         if (!errno)
  44.             return GUSI_error(ENOMEM);
  45.         else
  46.             return -1;
  47.     } else
  48.         return GUSI_error(EINVAL);
  49. }
  50.  
  51. int creat(const char* filename)
  52. {
  53.     return open(filename, O_WRONLY | O_TRUNC | O_CREAT);
  54. }
  55.  
  56. int remove(const char *filename)
  57. {
  58.     GUSIFileRef    ref(filename, FileSocketDomain::willRemove, true);
  59.     
  60.     if (ref.Domain())
  61.         return ref.Domain()->remove(ref);
  62.     else
  63.         return GUSI_error(EINVAL);
  64. }
  65.  
  66. int unlink(char* filename)
  67. {
  68.     GUSIFileRef    ref(filename, FileSocketDomain::willRemove, true);
  69.     
  70.     if (ref.Domain())
  71.         return ref.Domain()->remove(ref);
  72.     else
  73.         return GUSI_error(EINVAL);
  74. }
  75.  
  76. int rename(const char *oldname, const char *newname)
  77. {
  78.     GUSIFileRef    ref(oldname, FileSocketDomain::willRename, true);
  79.     
  80.     if (ref.Domain())
  81.         return ref.Domain()->rename(ref, newname);
  82.     else
  83.         return GUSI_error(EINVAL);
  84. }
  85.  
  86. void fsetfileinfo(char *filename, unsigned long newcreator, unsigned long newtype)
  87. {
  88.     GUSIFileRef    ref(filename, FileSocketDomain::willSetFileInfo);
  89.     
  90.     if (ref.Domain())
  91.         ref.Domain()->fsetfileinfo(ref, newcreator, newtype);
  92.     else
  93.         GUSI_error(EINVAL);
  94. }
  95.  
  96. void fgetfileinfo(char *filename, unsigned long * creator, unsigned long * type)
  97. {
  98.     GUSIFileRef    ref(filename, FileSocketDomain::willGetFileInfo);
  99.     
  100.     if (ref.Domain())
  101.         ref.Domain()->fgetfileinfo(ref, creator, type);
  102.     else
  103.         GUSI_error(EINVAL);
  104. }
  105.  
  106. int faccess(char* filename, unsigned int cmd, long* arg)
  107. {
  108.     GUSIFileRef    ref(filename, FileSocketDomain::willFAccess);
  109.     
  110.     if (ref.Domain())
  111.         return ref.Domain()->faccess(ref, cmd, arg);
  112.     else
  113.         return GUSI_error(EINVAL);
  114. }
  115.  
  116. int truncate(const char* filename, off_t offset)
  117. {
  118.     int    res;
  119.     int    fd    =     open(filename, O_RDWR);
  120.     
  121.     if (fd == -1)
  122.         return -1;
  123.     
  124.     res = ftruncate(fd, offset);
  125.  
  126.     close(fd);
  127.     
  128.     return res;
  129. }
  130.  
  131. int stat(const char * path, struct stat * buf)
  132. {
  133.     GUSIFileRef    ref(path, FileSocketDomain::willStat);
  134.     
  135.     if (ref.Domain())
  136.         return ref.Domain()->stat(ref, buf);
  137.     else
  138.         return GUSI_error(EINVAL);
  139. }
  140.  
  141. int    lstat(const char * path, struct stat * buf)
  142. {
  143.     GUSIFileRef    ref(path, FileSocketDomain::willStat, true);
  144.     
  145.     if (ref.Domain())
  146.         return ref.Domain()->stat(ref, buf);
  147.     else
  148.         return GUSI_error(EINVAL);
  149. }
  150.  
  151. int chmod(const char * filename, mode_t mode)
  152. {
  153.     GUSIFileRef    ref(filename, FileSocketDomain::willChmod);
  154.     
  155.     if (ref.Domain())
  156.         return ref.Domain()->chmod(ref, mode);
  157.     else
  158.         return GUSI_error(EINVAL);    
  159. }
  160.  
  161. int utime(const char * path, const struct utimbuf * times)
  162. {
  163.     GUSIFileRef    ref(path, FileSocketDomain::willUTime);
  164.     
  165.     if (ref.Domain())
  166.         return ref.Domain()->utime(ref, times);
  167.     else
  168.         return GUSI_error(EINVAL);
  169. }
  170.  
  171. int access(const char * path, int mode)
  172. {
  173.     GUSIFileRef    ref(path, FileSocketDomain::willAccess);
  174.     
  175.     if (ref.Domain())
  176.         return ref.Domain()->access(ref, mode);
  177.     else
  178.         return GUSI_error(EINVAL);
  179. }
  180.  
  181. /************************ class GUSIFileRef *************************/
  182.  
  183. #ifndef GUSI_DISPATCH
  184.  
  185. // Identifying a name starting with dev: as a file or a device is
  186. // a dangerous job. Currently, there is no possibility to entirely 
  187. // disable device interpretation, so we're using the following 
  188. // heuristics in order to minimize conflicts with real file names:
  189. //     - Any name corresponding to an existing file is a file
  190. //    - Any name not recognized by any device domain is a file
  191.  
  192. GUSIFileRef::GUSIFileRef(const char * name, FileSocketDomain::Request request, Boolean useAlias)
  193.     : hasInfo(false), name(name), file(name, useAlias)
  194. {
  195.     if (!::IsDevice(name) || (!file.Error() && file.Exists()))
  196.         goto isFile;
  197.  
  198.     spec         = nil;
  199.     domain    = FileSocketDomain::FindDomain(*this, request);
  200.     
  201.     if (!domain)
  202.         goto isFile;
  203.         
  204.     error     = noErr;
  205.         
  206.     return;    
  207.         
  208. isFile:    
  209.     spec     =     &file;
  210.     error =     file.Error();
  211.     domain=    FileSocketDomain::FindDomain(*this, request);
  212. }
  213.  
  214. GUSIFileRef::GUSIFileRef(short fRefNum, FileSocketDomain::Request request)
  215.     : hasInfo(false), name(nil), file(fRefNum)
  216. {
  217.     spec     =  &file;
  218.     error    =    file.Error();
  219.     domain=     FileSocketDomain::FindDomain(*this, request);
  220. }
  221.  
  222. const CInfoPBRec * GUSIFileRef::Info() const
  223. {
  224.     if (!hasInfo) {
  225.         if (!spec) {
  226.             ((GUSIFileRef *) this)->error = paramErr;
  227.             
  228.             return nil;
  229.         }
  230.         if (((GUSIFileRef *) this)->error = file.CatInfo(((GUSIFileRef *) this)->info))
  231.             return nil;
  232.         
  233.         ((GUSIFileRef *) this)->hasInfo = true;
  234.     } 
  235.         
  236.     return &info;    
  237. }
  238.  
  239. /************************ class FileSocketDomain *************************/
  240.  
  241. // Only the domain management part is found here. For the file specific part,
  242. // see GUSIFile.cp
  243.  
  244. FileSocketDomain *    FileSocketDomain::firstDeviceDomain = nil;
  245. FileSocketDomain *     FileSocketDomain::lastDeviceDomain  = nil;
  246. FileSocketDomain *    FileSocketDomain::firstFileDomain   = nil;
  247. FileSocketDomain *     FileSocketDomain::lastFileDomain    = nil;
  248.  
  249. void Enqueue(
  250.     FileSocketDomain *                             current, 
  251.     FileSocketDomain * FileSocketDomain::*    next,
  252.     FileSocketDomain **                             first, 
  253.     FileSocketDomain **                             last)
  254. {
  255.     current->*next = FileSockets;
  256.     
  257.     if (*last)
  258.         (*last)->*next = current;
  259.     else
  260.         *first = current;
  261.     
  262.     *last = current;
  263. }
  264.  
  265. void Dequeue(
  266.     FileSocketDomain *                             current, 
  267.     FileSocketDomain * FileSocketDomain::*    next,
  268.     FileSocketDomain **                             first, 
  269.     FileSocketDomain **                             last)
  270. {
  271.     FileSocketDomain * pred = nil;
  272.     
  273.     if (!*first)
  274.         return;
  275.         
  276.     if (*first == current)
  277.         *first = current->*next;
  278.     else {
  279.         for (pred = *first; pred->*next && pred->*next != current;)
  280.             pred = pred->*next;
  281.         if (pred->*next == current)
  282.             pred->*next = current->*next;
  283.         else
  284.             return;
  285.     }
  286.     
  287.     if (*last == current)
  288.         *last = pred;
  289. }
  290.  
  291. static Boolean                 HandleFileDispatch = true;
  292. static FileSocketDomain *    NullSockets;
  293.  
  294. FileSocketDomain::FileSocketDomain(
  295.     int         domain, 
  296.     Boolean     doesDevices, 
  297.     Boolean     doesFiles)
  298.     : SocketDomain(domain)
  299. {
  300.     if (!FileSockets && HandleFileDispatch) {
  301.         FileSockets = new FileSocketDomain;
  302.         NullSockets = new NullSocketDomain;
  303.     }
  304.         
  305.     if (doesDevices)
  306.         Enqueue(
  307.             this, 
  308.             &FileSocketDomain::nextDeviceDomain, &firstDeviceDomain, &lastDeviceDomain);
  309.     if (doesFiles)
  310.         Enqueue(
  311.             this, 
  312.             &FileSocketDomain::nextFileDomain, &firstFileDomain, &lastFileDomain);
  313. }
  314.  
  315. FileSocketDomain::~FileSocketDomain()
  316. {
  317.     if (this == FileSockets) {
  318.         FileSockets                =    nil;
  319.         HandleFileDispatch     = false;
  320.     }
  321.         
  322.     Dequeue(
  323.             this, 
  324.             &FileSocketDomain::nextDeviceDomain, &firstDeviceDomain, &lastDeviceDomain);
  325.     Dequeue(
  326.             this, 
  327.             &FileSocketDomain::nextFileDomain, &firstFileDomain, &lastFileDomain);
  328. }
  329.     
  330. FileSocketDomain * FileSocketDomain::FindDomain(
  331.     const GUSIFileRef & ref, Request request)
  332. {
  333.     FileSocketDomain *                             dom;
  334.     FileSocketDomain * FileSocketDomain::* next;
  335.     
  336.     // We are already decomposing
  337.     
  338.     if (!FileSockets)
  339.         if (!HandleFileDispatch)
  340.             return nil;
  341.         else 
  342.             FileSockets = new FileSocketDomain;
  343.         
  344.     if (ref.IsDevice()) {
  345.         dom     =     firstDeviceDomain;
  346.         next    =    &FileSocketDomain::nextDeviceDomain;
  347.     } else {
  348.         dom     =     firstFileDomain;
  349.         next    =    &FileSocketDomain::nextFileDomain;
  350.     }
  351.     
  352.     // FileSockets will handle *everything*, therefore loop guaranteed to terminate
  353.     
  354.     while (dom && !dom->Yours(ref, request))
  355.         dom = dom->*next;
  356.     
  357.     return dom;
  358. }
  359.  
  360. // Quod licet Jovi non licet bovi
  361.  
  362. FileSocketDomain::FileSocketDomain()
  363.     :    SocketDomain(AF_FILE)
  364. {
  365.     firstFileDomain = firstDeviceDomain = this;
  366.     nextFileDomain = nextDeviceDomain = nil;
  367. }
  368.  
  369. Boolean FileSocketDomain::Yours(const GUSIFileRef & ref, Request req)
  370. {
  371.     // We handle all plain files and willOpen/willStat for the console
  372.     if (!ref.IsDevice())
  373.         return true;
  374.     else if (req != willOpen && req != willStat)
  375.         return false;
  376.         
  377.     switch (ref.name[4] | 0x20) {
  378.     case 's':
  379.         if ((ref.name[5] | 0x20) != 't' || (ref.name[6] | 0x20) != 'd')
  380.             return false;
  381.         switch (ref.name[7] | 0x20) {
  382.         case 'i':
  383.             if ((ref.name[8] | 0x20) != 'n' || ref.name[9])
  384.                 return false;
  385.             return true;
  386.         case 'o':
  387.             if ((ref.name[8] | 0x20) != 'u' || (ref.name[9] | 0x20) != 't' || ref.name[10])
  388.                 return false;
  389.             return true;
  390.         case 'e':
  391.             if ((ref.name[8] | 0x20) != 'r' || (ref.name[9] | 0x20) != 'r' || ref.name[10])
  392.                 return false;
  393.             return true;
  394.         default:
  395.             return false;
  396.         }
  397.     case 'c':
  398.         if (    (ref.name[5] | 0x20) != 'o' || (ref.name[6] | 0x20) != 'n'
  399.             || (ref.name[7] | 0x20) != 's' || (ref.name[8] | 0x20) != 'o'
  400.             || (ref.name[9] | 0x20) != 'l' || (ref.name[10] | 0x20) != 'e'
  401.             || ref.name[11])
  402.             return false;
  403.         return true;
  404.     case 'n':
  405.         if (    (ref.name[5] | 0x20) != 'u' || (ref.name[6] | 0x20) != 'l'
  406.             || (ref.name[7] | 0x20) != 'l' || ref.name[8])
  407.             return false;
  408.         return true;
  409.     default:
  410.         return false;
  411.     }
  412. }
  413.  
  414. #endif // GUSI_DISPATCH
  415.